﻿#include  "Graph3D.h"
#include <QVTKOpenGLNativeWidget.h>
#include <vtkGenericOpenGLRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkAxesActor.h>
#include <vtkCamera.h>
#include <vtkLightKit.h>
#include <vtkOrientationMarkerWidget.h>
#include <vtkUnstructuredGrid.h>
#include <vtkScalarBarActor.h>
#include <vtkTextProperty.h>
#include <vtkProp.h>
#include <QHBoxLayout>
#include "commonDefines.h"
#include "FieldGraphGenerator.h"
#include <vtkXMLUnstructuredGridReader.h>
#include <vtkOutputWindow.h>
#include <QCoreApplication>
#include <QDebug>
#include <QSplitter>
#include "Graph3DSettings.h"
#include <vtkWindowToImageFilter.h>
#include <vtkImageResize.h>
#include <vtkJPEGWriter.h>

namespace
{
    void saveImageFromScreen(vtkWindow* window, int width, int height, QString fileName, bool autoSize)
    {
        vtkNew<vtkWindowToImageFilter> report_windowToImageFilter;
        vtkNew<vtkImageResize> report_resize;
        vtkNew<vtkJPEGWriter> report_writer;

        report_windowToImageFilter->SetInput(window);
        report_resize->SetInputConnection(report_windowToImageFilter->GetOutputPort());
        if (autoSize)
        {
            report_windowToImageFilter->Update();
            auto dimension = report_windowToImageFilter->GetOutput()->GetDimensions();
            report_resize->SetOutputDimensions(dimension[0], dimension[1], -1);
        }
        else
        {
            report_resize->SetOutputDimensions(width, height, -1);
        }
        report_resize->Update();
        report_writer->SetFileName(fileName.toStdString().c_str());
        report_writer->SetInputConnection(report_resize->GetOutputPort());
        report_writer->Write();
    }
}
namespace pst
{
    Graph3D::Graph3D(QWidget* parent)
        : QWidget(parent)
        , m_qvtkWidget(new QVTKOpenGLNativeWidget(this))
        , m_renderWindow3D(vtkSmartPointer<vtkGenericOpenGLRenderWindow> ::New())
        //, m_fieldGraphGenerator(std::shared_ptr<pst::FieldGraphGenerator>(new pst::FieldGraphGenerator()))
        , m_render3D(vtkSmartPointer<vtkRenderer>::New())
        , m_leftDownCornerAxes(vtkSmartPointer<vtkAxesActor>::New())
        , m_leftDownCornerWidget(vtkSmartPointer<vtkOrientationMarkerWidget>::New())
        , m_settings(new Graph3DSettings(this))
    {
        vtkOutputWindow::SetGlobalWarningDisplay(0);

        QHBoxLayout* layout = new QHBoxLayout(this);
        layout->setContentsMargins(0, 0, 0, 0);
        layout->setStretch(0, 1);
        layout->setStretch(1, 0);

        m_qvtkWidget->setRenderWindow(m_renderWindow3D);

        m_renderWindow3D->AddRenderer(m_render3D);
        m_render3D->GetActiveCamera()->SetParallelProjection(true);
        m_render3D->AutomaticLightCreationOff();
        m_render3D->SetUseDepthPeeling(1);
        m_render3D->SetBackground(1, 1, 1);
        vtkNew<vtkLightKit> lightKit;
        lightKit->AddLightsToRenderer(m_render3D);
        lightKit->SetKeyLightWarmth(0.5);
        lightKit->SetFillLightWarmth(0.5);
        lightKit->SetBackLightWarmth(0.5);
        lightKit->SetHeadLightWarmth(0.5);

        QSplitter* splitter = new QSplitter(Qt::Horizontal, this);
        splitter->addWidget(m_qvtkWidget);
        //splitter->addWidget(m_settings);
        splitter->setSizes({ 3000,1000 });
        layout->addWidget(splitter);

        AddCornerAxes();
        initConnections();
    }

    Graph3D::~Graph3D()
    {
    }

    void Graph3D::AddCornerAxes()
    {
        m_leftDownCornerAxes->SetPosition(0, 0, 0);
        m_leftDownCornerAxes->SetTotalLength(12, 12, 12);
        m_leftDownCornerAxes->SetShaftType(0);
        m_leftDownCornerAxes->SetCylinderRadius(0.02);

        m_leftDownCornerWidget->SetOrientationMarker(m_leftDownCornerAxes);
        m_leftDownCornerWidget->SetInteractor(m_renderWindow3D->GetInteractor());
        m_leftDownCornerWidget->KeyPressActivationOff();
        m_leftDownCornerWidget->SetEnabled(1);
        m_leftDownCornerWidget->InteractiveOff();

        //m_render3D->ResetCamera();
        //qvtkWidget->renderWindow()->Render();
    }

    void Graph3D::initConnections()
    {
        connect(m_settings, &Graph3DSettings::signal_scalarBarTitleChanged, this, &Graph3D::slot_scalarBarTitleChanged);
        connect(m_settings, &Graph3DSettings::signal_scalarBarFontTypeChanged, this, &Graph3D::slot_scalarBarFontTypeChanged);
        connect(m_settings, &Graph3DSettings::signal_scalarBarFontSizeChanged, this, &Graph3D::slot_scalarBarFontSizeChanged);
        connect(m_settings, &Graph3DSettings::signal_scalarBarMinValueChanged, this, &Graph3D::slot_scalarBarMinValueChanged);
        connect(m_settings, &Graph3DSettings::signal_scalarBarMaxValueChanged, this, &Graph3D::slot_scalarBarMaxValueChanged);
    }

    void Graph3D::addGraph3D(InfomationGraph3DBasical& info)
    {
        auto reader = info.m_reader;
        if (reader == nullptr)
        {
            return;
        }

        auto fieldGraphGenerator = new FieldGraphGenerator(this);
        m_fieldGraphGeneratorList.append(fieldGraphGenerator);
        m_currentFieldGraphGenerator = fieldGraphGenerator;

        fieldGraphGenerator->SetInputDataSet(reader->GetOutput());
        fieldGraphGenerator->SetScalarsScalarBarWidgetInteractor(m_renderWindow3D->GetInteractor());

        //获取标量场和矢量场
        auto pointArray = fieldGraphGenerator->GetPointsArrayIndexAndNames();
        auto cellArray = fieldGraphGenerator->GetCellsArrayIndexAndNames();
        for (int i = 0; i < pointArray.size(); i++)
        {
            //标量场
            m_allScalarFieldArray.push_back(pointArray[i]);
            //矢量场
            if (pointArray[i].arrayComponent == 3)
            {
                m_allVectorFieldArray.push_back(pointArray[i]);
            }
        }
        for (int i = 0; i < cellArray.size(); i++)
        {
            //标量场
            m_allScalarFieldArray.push_back(cellArray[i]);
            //矢量场
            if (cellArray[i].arrayComponent == 3)
            {
                m_allVectorFieldArray.push_back(cellArray[i]);
            }
        }

        if (m_allScalarFieldArray.isEmpty()) //为空，使用几何颜色
        {
            m_dataActor = fieldGraphGenerator->GetGeometryActor();
        }
        else
        {
            //使用第一个标量场
            const auto& currentField = m_allScalarFieldArray.at(0);
            auto isSetSuccess = fieldGraphGenerator->SetActiveScalarAttribute(
                currentField.arrayIndex, currentField.type, 0);
            if (!isSetSuccess)
            {
                return;
            }
            fieldGraphGenerator->UpdateScalarFieldActor();
            m_dataActor = fieldGraphGenerator->GetScalarsFieldActor();
            m_render3D->AddActor(m_dataActor);
            auto scalarBarActor = fieldGraphGenerator->GetScalarsFieldScalarBarActor();
            m_render3D->AddActor(scalarBarActor);
        }
        m_render3D->ResetCamera();
        m_renderWindow3D->Render();

        //设置初始值
        vtkScalarBarActor* scalarBarActor = m_currentFieldGraphGenerator->GetScalarsFieldScalarBarActor();
        m_settings->setScalarBarTitleName(scalarBarActor->GetTitle());
        slot_scalarBarFontTypeChanged("宋体");
        slot_scalarBarFontSizeChanged(24);
        auto range = m_currentFieldGraphGenerator->GetScalarBarRange(FieldGraphGenerator::FieldType::SCALARS);
        m_settings->setScalarBarMinMaxValue(range[0], range[1]);
    }

    bool Graph3D::saveScreenShot(const QString& path)
    {
        saveImageFromScreen(m_renderWindow3D, 1920, 1080, path, true);
        return true;
    }

    void Graph3D::addProp(QList<vtkProp*> props)
    {
        for (auto i : props)
        {
            m_render3D->AddActor(i);
        }
        m_render3D->ResetCamera();
        m_renderWindow3D->Render();
    }

    void Graph3D::slot_scalarBarTitleChanged(const QString& title)
    {
        m_currentFieldGraphGenerator->SetScalarBarTitle(
            title, FieldGraphGenerator::FieldType::SCALARS);
        m_renderWindow3D->Render();
    }

    void Graph3D::slot_scalarBarFontTypeChanged(QString fontType)
    {
        vtkScalarBarActor* scalarBarActor = m_currentFieldGraphGenerator->GetScalarsFieldScalarBarActor();
        if (fontType == "微软雅黑") //并非真正的微软雅黑
        {
            QString currenEXEPath = QCoreApplication::applicationDirPath();
            auto micFont = currenEXEPath + "/Fonts/Alibaba-PuHuiTi-Regular.ttf";
            scalarBarActor->GetTitleTextProperty()->SetFontFamily(VTK_FONT_FILE);
            scalarBarActor->GetTitleTextProperty()->SetFontFile(micFont.toLocal8Bit());
        }
        else if (fontType == "宋体") //并非真正的宋体
        {
            QString currenEXEPath = QCoreApplication::applicationDirPath();
            auto songFont = currenEXEPath + "/Fonts/TangXianBinSong-2.otf";
            scalarBarActor->GetTitleTextProperty()->SetFontFamily(VTK_FONT_FILE);
            scalarBarActor->GetTitleTextProperty()->SetFontFile(songFont.toLocal8Bit());
        }
        m_renderWindow3D->Render();
    }

    void Graph3D::slot_scalarBarFontSizeChanged(int fontSize)
    {
        vtkScalarBarActor* scalarBarActor = m_currentFieldGraphGenerator->GetScalarsFieldScalarBarActor();
        scalarBarActor->SetUnconstrainedFontSize(true);
        scalarBarActor->GetTitleTextProperty()->SetFontSize(fontSize);
        m_renderWindow3D->Render();
    }

    void Graph3D::slot_scalarBarMinValueChanged(double minValue)
    {
        vtkScalarBarActor* scalarBarActor = m_currentFieldGraphGenerator->GetScalarsFieldScalarBarActor();
        auto range = m_currentFieldGraphGenerator->GetScalarBarRange(FieldGraphGenerator::FieldType::SCALARS);
        m_currentFieldGraphGenerator->SetScalarBarRange(minValue, range[1], FieldGraphGenerator::FieldType::SCALARS);
        m_renderWindow3D->Render();
    }

    void Graph3D::slot_scalarBarMaxValueChanged(double maxValue)
    {
        vtkScalarBarActor* scalarBarActor = m_currentFieldGraphGenerator->GetScalarsFieldScalarBarActor();
        auto range = m_currentFieldGraphGenerator->GetScalarBarRange(FieldGraphGenerator::FieldType::SCALARS);
        m_currentFieldGraphGenerator->SetScalarBarRange(range[0], maxValue, FieldGraphGenerator::FieldType::SCALARS);
        m_renderWindow3D->Render();
    }
}
